package com.sinodata.bsm.cicp.util.telnet.pool;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.util.telnet.EthzSSH;

/**
 * 
 * <p>
 * Description: 以ganymed框架重写的EthzSSH2连接池
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-15 PM 3:31:22     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class EthzSSH2Pool {

    private static Logger log = Logger.getLogger(EthzSSH2Pool.class);

    private final Map<String, SSH2Lock> ssh2Maps = new HashMap<String, SSH2Lock>();

    private static EthzSSH2Pool instance = null;

    private static Map<String, Object> ssh2ConnectLocks = new HashMap<String, Object>();

    private EthzSSH2Pool() {

    }

    /**
     * 以单例模式获取连接池实例
     */
    public synchronized static EthzSSH2Pool getInstance() {
        if (instance == null) {
            instance = new EthzSSH2Pool();
        }
        return instance;
    }

    /**
     * 1. 设置最大连接数 2. 如果list中有可用连接则取出一个 3. 如果没用则新生成一个
     * @param host 主机IP
     * @param port 主机端口
     * @param user 用户
     * @param pwd  密码
     * @param maxConnSize 最大连接数
     * @return
     */
    public EthzSSH getConnection(String host, int port, String user, String pwd, int maxConnSize) {
        SSH2Lock ssh2Lock = getSSH2Lock(host);
        if (ssh2Lock.getMaxSize() != maxConnSize) {
            ssh2Lock.setMaxSize(maxConnSize);
        }
        if (!ssh2Lock.isConnectable()) {
            log.info("Host--" + host + "--has no available connections of SSH2");
        }
        ssh2Lock.lock();
        try {
            synchronized (ssh2Lock.getSSH2List()) {
                if (ssh2Lock.getSSH2List().size() > 0) {
                    return ssh2Lock.getSSH2List().removeFirst();
                }
            }
            Object lock = null;
            synchronized (ssh2ConnectLocks) {
                lock = ssh2ConnectLocks.get(host);
                if (lock == null) {
                    ssh2ConnectLocks.put(host, new Object());
                    lock = ssh2ConnectLocks.get(host);
                }
            }
            synchronized (lock) {
                EthzSSH ethzssh = new EthzSSH();
                ethzssh.login(host, port, user, pwd);
                ethzssh.setValid(true);
                //                Connection conn = ethzssh.getConn();
                //                                Session session = conn.openSession();
                //                                session.execCommand("bash");
                //                                session.close();
                //                                session = conn.openSession();
                //                                session.execCommand("LANG=C;export LANG");
                //                                session.close();
                //                                session = conn.openSession();
                ssh2Lock.setConnectable(true);
                return ethzssh;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    //释放连接
    public void freeSSH2(String host, EthzSSH ethzssh) throws Exception {
        getSSH2Lock(host).free(ethzssh);
    }

    //获取一个SSH2Lock
    private synchronized SSH2Lock getSSH2Lock(String host) {
        SSH2Lock ssh2Lock = ssh2Maps.get(host);
        if (ssh2Lock == null) {
            ssh2Lock = new SSH2Lock(host);
            ssh2Maps.put(host, ssh2Lock);
        }
        return ssh2Lock;
    }

    public void freeSSH2(String host) throws Exception {
        //        synchronized (ssh2Maps) {
        //            SSH2Lock old = ssh2Maps.get(host);
        //            old = null;
        //            SSH2Lock ssh2Lock = new SSH2Lock(host);
        //            ssh2Maps.put(host, ssh2Lock);
        //        }

        //        System.out.println("修改了用户名或密码");

        log.info("修改了用户名或密码");
    }

    /**
     *
     * <p>
     * Description: 内部类用来存放以下信息
     * 1 最大连接数 2 当前连接数  3 存放可用连接的LIST列表
     * </p>
     *
     * @author wangyz
     * @version 3.0

     * <p>
     * History:
     *
     * Date                     Author         Version     Description
     * ---------------------------------------------------------------------------------
     * Mar 28, 2011 10:16:36 AM          wangyz        3.0         To create
     * </p>
     *
     * @since
     * @see
     */
    class SSH2Lock {

        protected String host;

        protected int currentSize = 0;

        protected int maxSize = 10;

        protected boolean connectable = true;

        protected LinkedList<EthzSSH> ssh2List = new LinkedList<EthzSSH>();

        public SSH2Lock(String host) {
            this.host = host;
        }

        /**
         * 获取连接前先加锁
         *
         */
        public synchronized void lock() {
            while (currentSize >= maxSize) {
                try {
                    wait();
                } catch (Exception e) {
                    log.error("Failed to get a available connection!");
                }
            }
            currentSize++;
        }

        /**
         * 1 如果连接可用则将其加入到list
         * 2 否则则将连接关闭
         * @param ethzssh
         * @throws Exception
         */
        public synchronized void free(EthzSSH ethzssh) throws Exception {
            currentSize--;
            if (ethzssh.getValid() == true) {
                ssh2List.addLast(ethzssh);
            } else {
                ethzssh.disconn();
            }
            notifyAll();
        }

        public synchronized boolean isConnectable() {
            return connectable || (currentSize < maxSize);
        }

        public synchronized void setConnectable(boolean connectable) {
            this.connectable = connectable;
        }

        public int getMaxSize() {
            return maxSize;
        }

        public void setMaxSize(int maxSize) {
            this.maxSize = maxSize;
        }

        public synchronized LinkedList<EthzSSH> getSSH2List() {
            return ssh2List;
        }

        public synchronized void setSSH2List(LinkedList<EthzSSH> ssh2List) {
            this.ssh2List = ssh2List;
        }

    }
}
